package Lib3d.MyUtils;


import Lib3d.Object3d;
import Lib3d.Vector3d;

import java.util.Vector;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;

/**
 * The bouding Box classe implementation.
 * 
 * @author Wassim Chegham
 * @version 0.1
 * @category Lib3d.MyUtils
 * 
 */
public class BoundingBox {

    /**
     * Private class that holds the minimum and maximum values
     * 
     * @author {@link <a href="cheghamwassim.com>Wassim Chegham<a> }
     * 
     */
    private class MinMax {
        private final float min, max;

        public MinMax(final float min, final float max) {
            this.min = min;
            this.max = max;
        }

        public boolean intersect(final MinMax mm) {
            return this.max >= mm.min || mm.max >= this.min;
        }
    }

    private Vector3d max;
    private Vector3d min;

    public BoundingBox(final Object3d object3d) {
        this.min = new Vector3d(0f, 0f, 0f);
        this.max = new Vector3d(0f, 0f, 0f);

        this.computeBBoxOfObject(object3d.getVertices());

    }

    public BoundingBox(final Vector<Object3d> objects3d) {
        this.min = new Vector3d(0f, 0f, 0f);
        this.max = new Vector3d(0f, 0f, 0f);

        Object3d obj;
        Vector<Vector3d> vv;
        for (int i = 0; i < objects3d.size(); i++) {

            obj = objects3d.get(i);
            vv = obj.getVertices();

            this.computeBBoxOfObject(vv);

        }
    }

    public void drawComponentBBox(final GLAutoDrawable gLDrawable) {
        final GL gl = gLDrawable.getGL();

        final Vector3d p1 = this.max;
        final Vector3d p2 = this.min;
        final Vector3d p3 = new Vector3d(this.max.get(0), this.min.get(1),
                this.min.get(2));
        final Vector3d p4 = new Vector3d(this.max.get(0), this.min.get(1),
                this.max.get(2));
        final Vector3d p5 = new Vector3d(this.min.get(0), this.min.get(1),
                this.max.get(2));
        final Vector3d p6 = new Vector3d(this.min.get(0), this.max.get(1),
                this.max.get(2));
        final Vector3d p7 = new Vector3d(this.min.get(0), this.max.get(1),
                this.min.get(2));
        final Vector3d p8 = new Vector3d(this.max.get(0), this.max.get(1),
                this.min.get(2));

        gl.glBegin(GL.GL_LINE_LOOP);
        gl.glVertex3fv(p1.toBuffer());
        gl.glVertex3fv(p6.toBuffer());
        gl.glVertex3fv(p7.toBuffer());
        gl.glVertex3fv(p8.toBuffer());
        gl.glEnd();

        gl.glBegin(GL.GL_LINE_STRIP);
        gl.glVertex3fv(p1.toBuffer());
        gl.glVertex3fv(p4.toBuffer());
        gl.glVertex3fv(p3.toBuffer());
        gl.glVertex3fv(p8.toBuffer());
        gl.glEnd();

        gl.glBegin(GL.GL_LINE_STRIP);
        gl.glVertex3fv(p3.toBuffer());
        gl.glVertex3fv(p2.toBuffer());
        gl.glVertex3fv(p7.toBuffer());
        gl.glEnd();

        gl.glBegin(GL.GL_LINE_STRIP);
        gl.glVertex3fv(p2.toBuffer());
        gl.glVertex3fv(p5.toBuffer());
        gl.glVertex3fv(p6.toBuffer());
        gl.glEnd();

        gl.glBegin(GL.GL_LINE_STRIP);
        gl.glVertex3fv(p5.toBuffer());
        gl.glVertex3fv(p4.toBuffer());
        gl.glEnd();

    }

    public MinMax getMinMaxOfX() {
        return new MinMax(this.min.get(0), this.max.get(0));
    }

    public MinMax getMinMaxOfY() {
        return new MinMax(this.min.get(1), this.max.get(1));
    }

    public MinMax getMinMaxOfZ() {
        return new MinMax(this.min.get(2), this.max.get(2));
    }

    public boolean interset(final BoundingBox bb) {
        return this.getMinMaxOfX().intersect(bb.getMinMaxOfX())
                && this.getMinMaxOfY().intersect(bb.getMinMaxOfY())
                && this.getMinMaxOfZ().intersect(bb.getMinMaxOfZ());
    }

    private void computeBBoxOfObject(final Vector<Vector3d> vv) {
        Vector3d v;
        for (int j = 0; j < vv.size(); j++) {

            v = vv.get(j);

            if (v.get(0) < this.min.get(0)) {
                this.min = new Vector3d(v.get(0), this.min.get(1), this.min.get(2));
            }
            else if (v.get(0) > this.max.get(0)) {
                this.max = new Vector3d(v.get(0), this.max.get(1), this.max.get(2));
            }
            if (v.get(1) < this.min.get(1)) {
                this.min = new Vector3d(this.min.get(0), v.get(1), this.min.get(2));
            }
            else if (v.get(1) > this.max.get(1)) {
                this.max = new Vector3d(this.max.get(0), v.get(1), this.max.get(2));
            }
            if (v.get(2) < this.min.get(2)) {
                this.min = new Vector3d(this.min.get(0), this.min.get(1), v.get(2));
            }
            else if (v.get(2) > this.max.get(2)) {
                this.max = new Vector3d(this.max.get(0), this.max.get(1), v.get(2));
            }
        }

    }
}
